/*
 *Copyright (c) 2024 Black Sesame Technologies
 *
 *Licensed under the Apache License, Version 2.0 (the "License");
 *you may not use this file except in compliance with the License.
 *You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *Unless required by applicable law or agreed to in writing, software
 *distributed under the License is distributed on an "AS IS" BASIS,
 *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *See the License for the specific language governing permissions and
 *limitations under the License.
*/

#ifndef SQ_BUFFER_H
#define SQ_BUFFER_H

#include <stdint.h>

#define SQ_BUFFER_NUM_MAX 16
#define SQ_BUFFER_CONSUMER_MAX 16

// 定义SQE结构体
typedef struct SQE {
    int32_t ref_cnt;  // 引用计数
    int32_t index;
    void *buffer;                // 实际数据指针
} SQE;

// 定义SQ结构体
typedef struct free_SQ {
    SQE sqe[SQ_BUFFER_NUM_MAX];  // 保存实际SQE
} free_SQ;

typedef struct data_SQ {
    int32_t front;
    int32_t rear;
    int32_t sqe_ptr[SQ_BUFFER_NUM_MAX];  // 保存SQE在free_SQ中的索引
} data_SQ;

typedef struct SQ_Buffer {
    int32_t buffer_size;  // buffer中数据块的大小
    int32_t buffer_num;   // 可用的buffer数据块的数量， 用户传入
    free_SQ free_sq;      // 空闲SQ
    data_SQ data_sq[SQ_BUFFER_CONSUMER_MAX];  // data_SQ 数组, 每个消费者一个
    uint64_t buffers_phy_addr64[SQ_BUFFER_NUM_MAX];  // 缓冲区64位物理地址
} SQ_Buffer;

/*
 * @brief 初始化 SQ_Buffer
 * @param sq 要初始化的 SQ_Buffer
 * @param buffer buffer数组
 * @param buffer_size 每个buffer的大小
 * @param buffer_num buffer数量
 * @return 如果 SQ_Buffer 初始化成功返回 0，否则返回 -1
 */
int SQ_Buffer_Init(SQ_Buffer *sq, void **buffer, int32_t buffer_size,
                   int32_t buffer_num);

/*
 * @brief 生产端从 SQ_Buffer 获取一个 SQE
 * @param sq 要保存生产数据的 SQ_Buffer
 * @return 如果获取成功返回 SQE, 否则返回 NULL
 */
SQE *SQ_Buffer_Produce_Get(SQ_Buffer *sq);

/*
 * @brief 将生产的数据放入 SQ_Buffer
 * @param sq 要放入数据的 SQ_Buffer
 * @param sqe 要放入的 SQE
 * @param consumer_mask 消费者掩码, 每个 bit
 * 代表是否需要将数据放入该消费者的data_SQ
 * @return 如果数据放入成功返回 0, 否则返回 -1
 */
int SQ_Buffer_Produce_Put(SQ_Buffer *sq, SQE *sqe, uint16_t consumer_mask);

/*
 * @brief 消费者端从 SQ_Buffer 消费一个 SQE
 * @param sq 要消费数据的 SQ_Buffer
 * @param consumer_id 消费者ID, 0~5
 * @return 如果消费成功返回 SQE, 否则返回 NULL
 */
SQE *SQ_Buffer_Consume_Get(SQ_Buffer *sq, uint8_t consumer_id);

/*
 * @brief 将消费的 SQE 放回 SQ_Buffer
 * @param sq 要放回 SQE 的 SQ_Buffer
 * @param sqe 要放回的 SQE
 * @return 如果 SQE 放回成功, 返回 0, 否则返回 -1
 */
int SQ_Buffer_Consume_Put(SQ_Buffer *sq, SQE *sqe);

#endif
